package gestores;

import android.app.Application;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;

import clasesAuxiliares.ItemPesoRelativoCriterio;
import clasesAuxiliares.Resultado;
import modelo.Comparacion;
import modelo.Item;
import modelo.MatrizComparacionAlternativas;
import modelo.MatrizComparacionCriterios;

/**
 * Created by Usuario on 03/11/2014.
 */
public class GestorModeloAHP extends Application {
    private MatrizComparacionCriterios matrizCriterios;
    private HashMap<Item, MatrizComparacionAlternativas> matricesAlternativas;
    private static double[] indiceAleatorio = {0, 0.58, 0.9, 1.12,
            1.24, 1.32, 1.41};
    private ArrayList<Item> alternativas;
    private double lambdaMax;
    private double indRC;
    private double indIC;
    private double indIA;


    /**
     * Called when the application is starting, before any activity, service,
     * or receiver objects (excluding content providers) have been created.
     * Implementations should be as quick as possible (for example using
     * lazy initialization of state) since the time spent in this function
     * directly impacts the performance of starting the first activity,
     * service, or receiver in a process.
     * If you override this method, be sure to call super.onCreate().
     */
    @Override
    public void onCreate() {
        super.onCreate();
        matrizCriterios = new MatrizComparacionCriterios();
        matricesAlternativas = new HashMap<Item, MatrizComparacionAlternativas>();
        alternativas = new ArrayList<Item>();
    }

    /**
     * Mètodo para saber si la matriz de criterios es consistente o no.
     *
     * @return TRVE si es consistente
     * FALSE si presenta inconsistencias.
     */
    public boolean verificarConsistencia() {
        int n = getSizeMatrizBase(true);
        //double indRC = 0;
        boolean band = false;

        if (n != 2) {
             lambdaMax = matrizCriterios.calcularLambdaMax();

             indIA = indiceAleatorio[n - 2]; //CHEQUEAR ESTO!!

            indIC = (lambdaMax - n) / (n - 1);
            indRC = indIC / indIA;
        }else{
            indRC = 0;
        }

        System.out.println(indRC);

        if (indRC < 0.1) {
            band = true;
        }
        return band;
    }

    public ArrayList<Double> testPesoRelativo(Item crit) {

        return matricesAlternativas.get(crit).calcularPesosRelativos();

    }

    /**
     * Método para agregar criterios y alternativas, según la bandera
     *
     * @param nombre
     * @param band   TRVE si es criterio
     *               FALSE si es alternativa
     */
    public void addItem(String nombre, boolean band) {
        if (band == true) {
            this.matrizCriterios.addItem(nombre);
        } else {
            Item it = new Item(alternativas.size(), nombre);
            alternativas.add(it);
        }
    }

    /**
     * Método para construir la matriz ya sea de criterios o de alternativas.
     *
     * @param band TRVE si es para la matriz de criterios
     *             FALSE si es para la de alternativas. Construye el map
     */
    public void construirMatriz(boolean band) {
        if (band == true) {
            matrizCriterios.inicializarMatriz();
        } else {
            for (Item criterio : matrizCriterios.getItemsComparados()) {
                matricesAlternativas.put(criterio, new MatrizComparacionAlternativas(alternativas));
            }
        }
    }

    /**
     * Método para comparar dos items pasados desde la intefaz.
     *
     * @param primerTermino
     * @param segundoTermino
     * @param puntaje
     */
    public void compararItems(Item primerTermino, Item segundoTermino, double puntaje) {
        this.matrizCriterios.comparar(primerTermino, segundoTermino, puntaje);
    }

    /**
     * Método para comparar alternativas. Se le pasa un item criterio para que busque las alternativas hijas
     * en el mapa. Despues se buscan las alternativas comparadas.
     *
     * @param primerTermino
     * @param segundoTermino
     * @param puntaje
     * @param criterio
     */
    public void compararAlternativas(Item primerTermino, Item segundoTermino, double puntaje, Item criterio) {
        matricesAlternativas.get(criterio).comparar(primerTermino, segundoTermino, puntaje);
    }

    public Item getItemByNombre(String nombre, boolean band) {
        if (band == true) {
            return matrizCriterios.getItemByNombre(nombre);
        }
        return null;
    }

    public Item getAlternativaByNombre(Item criterio, String nAlternativa) {
        for (Item alternativa : matricesAlternativas.get(criterio).getItemsComparados()) {
            if (alternativa.getNombre().equalsIgnoreCase(nAlternativa))
                return alternativa;
        }
        return null;
    }

    /**
     * Devuelve la lista de criterios definidos.
     *
     * @return
     */
    public ArrayList<Item> getListaCriterios() {
        return this.matrizCriterios.getItemsComparados();
    }

    /**
     * Devuelve el tamaño de la matriz de comparaciones.
     *
     * @param band TRVE si es criterio
     *             FALSE si es alternativa
     * @return
     */
    public int getSizeMatrizBase(boolean band) {
        if (band == true)
            return getListaCriterios().size();
        else
            return getAlternativas().size();
    }

    /**
     * Para buscar un término comparado por ID.
     *
     * @param band TRVE si es criterio
     *             FALSE si es alternativa
     * @return
     */
    public Item getItemById(int idItem, boolean band) {
        if (band == true) {
            return matrizCriterios.getItemById(idItem);
        } else {
            for (Item it : alternativas) {
                if (it.getId() == idItem)
                    return it;
            }
        }
        return null;
    }


    public MatrizComparacionCriterios getMatrizCriterios() {
        return matrizCriterios;
    }

    public void setMatrizCriterios(MatrizComparacionCriterios matrizCriterios) {
        this.matrizCriterios = matrizCriterios;
    }

    public HashMap<Item, MatrizComparacionAlternativas> getMatricesAlternativas() {
        return matricesAlternativas;
    }

    public void setMatricesAlternativas(HashMap<Item, MatrizComparacionAlternativas> matricesAlternativas) {
        this.matricesAlternativas = matricesAlternativas;
    }

    public ArrayList<Item> getAlternativas() {
        return alternativas;
    }


    public static double[] getIndiceAleatorio() {
        return indiceAleatorio;
    }

    public static void setIndiceAleatorio(double[] indiceAleatorio) {
        GestorModeloAHP.indiceAleatorio = indiceAleatorio;
    }

    public ArrayList<Comparacion> getMatrizBaseCriterios() {
        return matrizCriterios.getMatrizBase();
    }

    public void inicializarMatrizBaseCriterios() {
        this.getMatrizCriterios().inicializarMatriz();
    }

    /**
     * Construye el hashmap para pasarle al adapter del step2
     *
     * @return
     */
    public HashMap<Item, ArrayList<Comparacion>> buildDataChildren() {
        HashMap<Item, ArrayList<Comparacion>> mapa = new HashMap<Item, ArrayList<Comparacion>>();

        for (Item it : getListaCriterios()) {
            ArrayList<Comparacion> lstAuxiliar = new ArrayList<Comparacion>();
            for (Comparacion c : getMatrizBaseCriterios()) {
                if (c.getPrimerTermino() == it) {
                    lstAuxiliar.add(c);
                }
                mapa.put(it, lstAuxiliar);
            }
        }
        return mapa;
    }

    public HashMap<Item, ArrayList<Comparacion>> buildDataChildrenStep4(int idCriterio) {
        Item criterio = getItemById(idCriterio, true);

        HashMap<Item, ArrayList<Comparacion>> mapa = new HashMap<Item, ArrayList<Comparacion>>();
        MatrizComparacionAlternativas mtzAlt = getMatricesAlternativas().get(criterio);

        for (Item it : mtzAlt.getItemsComparados()) {
            ArrayList<Comparacion> hijos = new ArrayList<Comparacion>();
            for (Comparacion c : mtzAlt.getMatrizBase()) {
                if (c.getPrimerTermino() == it) {
                    hijos.add(c);
                }
            }
            mapa.put(it, hijos);
        }

        return mapa;
    }

    public ArrayList<Item> buildDataParentsStep4(int idCriterio) {
        Item criterio = null;
        for (Item it : matricesAlternativas.keySet()) {
            if (it.getId() == idCriterio)
                criterio = it;
        }
        MatrizComparacionAlternativas mtzAlt = getMatricesAlternativas().get(criterio);
        return mtzAlt.getItemsComparados();
    }

    public HashMap<Item, ArrayList<Item>> construirMatrizAlternativa(Item criterio) {
        HashMap<Item, ArrayList<Item>> mapaAux = new HashMap<Item, ArrayList<Item>>();

        MatrizComparacionAlternativas mc = matricesAlternativas.get(criterio);
        for (Item it : mc.getItemsComparados()) {
            ArrayList<Item> itemsSegundoTermino = new ArrayList<Item>();
            for (Comparacion c : mc.getMatrizBase()) {
                if (c.getPrimerTermino() == it) {
                    itemsSegundoTermino.add(c.getSegundoTermino());
                }
            }
            mapaAux.put(it, itemsSegundoTermino);
        }
        return mapaAux;
    }

    //----------------------------Metodos para resolver la matriz----------------------------//

    /**
     * Para cada criterio calcula los pesos relativos y va armando la matriz global.
     *
     * @return
     */

    public ArrayList<Resultado> construirMatrizGlobal() {
        int indCol = 0;
        ArrayList<Double> pCriterios = matrizCriterios.calcularPesosRelativos();
        double[] resAcumulado = new double[alternativas.size()];
        ArrayList<Resultado> lista = new ArrayList<Resultado>();

        for (Item crit : matricesAlternativas.keySet()) {
            int ind = 0;
            ArrayList<Double> pesosRelativos = matricesAlternativas.get(crit).calcularPesosRelativos();
            for (Double d : pesosRelativos) {
                d = d * pCriterios.get(crit.getId());
                resAcumulado[ind] += d;
                ind++;
            }
        }

        for(Item alt : alternativas){
            Resultado r = new Resultado(alt, resAcumulado[alt.getId()]);
            lista.add(r);
        }


        Collections.sort(lista, new Comparator<Resultado>() {
            @Override
            public int compare(Resultado r1, Resultado r2) {
                return new Double(r2.getPuntaje()).compareTo(new Double(r1.getPuntaje()));
            }
        });
        return lista;
    }

    /**
     * De la lista de puntajes , busca el mayor y devuelve el indice.
     *
     * @return

    public Resultado evaluacionGlobal() {
        int idAlternativaElegida = 0;
        double maxPuntaje = 0;
       // double[] puntajeAlt = construirMatrizGlobal();

        for (int i = 0; i < puntajeAlt.length; i++) {
            if (puntajeAlt[i] > maxPuntaje) {
                maxPuntaje = puntajeAlt[i];
                idAlternativaElegida = i;
            }

        }

        Item itemGanador = this.getItemById(idAlternativaElegida, false);
        Resultado r = new Resultado(itemGanador, maxPuntaje);
        return r;
    }*/

    /**
     * A partir del índice, busca en las alternativas y devuelve la ganadora.
     *
     * @return item alternativa.
     * <p/>
     * public Item getAlternativaGanadora(){
     * int indice = evaluacionGlobal();
     * for(Item alt : alternativas){
     * if(alt.getId() == indice)
     * return alt;
     * }
     * return null;
     * }
     */
    public void modificarItem(int idItem, String nombre, boolean band) {
        if (band == true) {
            for (Item cri : getListaCriterios()) {
                if (cri.getId() == idItem) {
                    cri.setNombre(nombre);
                }
            }
        } else {
            for (Item alt : alternativas) {
                if (alt.getId() == idItem) {
                    alt.setNombre(nombre);
                }
            }
        }
    }

    public void setAlternativas(ArrayList<Item> alternativas) {
        this.alternativas = alternativas;
    }

    public double getLambdaMax() {
        return lambdaMax;
    }

    public void setLambdaMax(double lambdaMax) {
        this.lambdaMax = lambdaMax;
    }

    public double getIndRC() {
        return indRC;
    }

    public void setIndRC(double indRC) {
        this.indRC = indRC;
    }

    public double getIndIC() {
        return indIC;
    }

    public void setIndIC(double indIC) {
        this.indIC = indIC;
    }

    public ArrayList<ItemPesoRelativoCriterio> getCriteriosPesosRelativos(){
        return matrizCriterios.getPesoRelativoCriterios();

    }
}

